package com.xwj.jdk8.lambda;

import com.xwj.jdk8.lambda.pojo.Person;
import com.xwj.jdk8.lambda.util.MyCompare;
import com.xwj.jdk8.lambda.util.TriFunction;
import com.xwj.jdk8.lambda.util.Utils;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.function.*;

/**
 * @Author: xiaowajiang
 * @Date: 2022-05-10 21:33
 * @Description:
 **/
public class LambdaTest {

    public static void main(String[] args) throws Exception {
        List<Person> list = Arrays.asList(new Person("张三", 23), new Person("李四", 30), new Person("王五", 40), new Person("赵六", 34));

        LambdaTest test = new LambdaTest();
        System.out.println("test_1");
        test.test_1();

        System.out.println(" \n\n test_2");
        test.test_2();

        System.out.println(" \n\n test_3");
        test.test_3();

        System.out.println(" \n\n test_4");
        List<Person> ageThan35 = test.test_4(list);
        System.out.println("年龄大于35的Person");
        ageThan35.forEach(i -> System.out.println(i));

        System.out.println(" \n\n test_5");
        test.test_5();

        System.out.println(" \n\n test_6");
        test.test_6();

        System.out.println(" \n\n test_7");
        test.test_7();

        System.out.println(" \n\n test_8");
        test.test_8();

        System.out.println(" \n\n test_9");
        test.test_9();

        System.out.println(" \n\n test_10");
        test.test_10();

        System.out.println(" \n\n test_11");
        test.test_11();

        System.out.println(" \n\n test_12");
        test.test_12();

        System.out.println(" \n\n test_13");
        test.test_13();
    }

    /**
     * Java8之前使用内部类创建一个线程
     */
    public void test_1() {
        Thread t = new Thread(new Runnable() {
            public void run(){
                System.out.println("内部类创建一个线程：Hello world");
            }
        });
        t.run();
    }

    /**
     * 使用Lambda表达式创建一个线程
     */
    public void test_2() {
        Thread t = new Thread(() -> System.out.println("Lambda表达式创建一个线程：Hello world"));
        t.run();
    }

    /**
     * Lambda表达式的使用示例
     */
    public void test_3() {
        // 1. 无参，无返回值
        Runnable r = () -> System.out.println("无参，无返回值");
        r.run();

        // 2. 有一个参数，无返回值(若只有一个参数时，小括号可以不写)
        Consumer<String> con = x -> System.out.println(x);
        con.accept("有一个参数，无返回值(若只有一个参数时，小括号可以不写)");

        // 3. 有两个及以上的参数，有返回值，并且Lambda体有多条语句
        Comparator<Integer> com = (x, y) -> {
            int compare = Integer.compare(x, y);
            return compare;
        };
        System.out.println("有两个及以上的参数，有返回值，并且Lambda体有多条语句:" + com.compare(1, 3));

        // 4. 若Lambda体仅有一条语句，return和大括号可以省略
        Comparator<Integer> com2 = (x, y) -> Integer.compare(x, y);
        System.out.println("若Lambda体仅有一条语句，return和大括号可以省略:" + com2.compare(1, 3));
    }

    /**
     * 类型检查
     * @param list
     * @return
     */
    public List<Person> test_4(List<Person> list) {
        List<Person> ageThan35 = filter(list, (Person p) -> p.getAge() > 35);
        return ageThan35;
    }

    /**
     * 数据过滤
     * @param list
     * @param p
     * @param <T>
     * @return
     */
    private <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> result = new ArrayList<>();
        for (T e: list) {
            if (p.test(e)) {
                result.add(e);
            }
        }
        return result;
    }

    /**
     * 局部变量使用限制，局部变量必须是最终态
     */
    public void test_5() {
        int x = 1;
        Runnable runnable = () -> {
            // Variable used in lambda expression should be final or effectively final
            // System.out.println(x++);
            System.out.println(x);
        };
        runnable.run();
    }

    /**
     * Lambda表达式是对值类型封闭，对引用类型开放。
     * @throws Exception
     */
    public void test_6() throws Exception {
        IntHolder holder = new IntHolder();
        Callable callable = () -> {
            // 编译通过 - 使用了引用类型
            holder.x++;
            return holder;
        };
        IntHolder call = (IntHolder) callable.call();
        System.out.println("变更后：" + call.x);
    }

    private static class IntHolder {
        int x = 1;
    }

    /**
     * 静态方法引用
     * 如果我们在Lambda表达式中要调用某个类的静态方法，并且这个静态方法的参数列表和函数式接口中抽象方法的参数列表相对应时，我们可以采用静态方法引用来处理。
     */
    public void test_7() {
        List<Integer> list = Arrays.asList(4, 6, 1, 2, 7);
        List<Integer> list2 = Arrays.asList(4, 6, 1, 2, 7);

        // Lambda表达式
        Collections.sort(list, (o1, o2) -> Utils.compare(o1, o2));
        System.out.println("静态方法引用 - Lambda表达式 " + list);
        // 静态方法引用
        Collections.sort(list2, Utils::compare);
        System.out.println("静态方法引用 - 类::静态方法 " + list2);
    }

    /**
     * 对象方法引用
     * 与引用静态方法类似，只不过在传递方法时，需要一个对象的存在。
     */
    public void test_8() {
        List<Integer> list = Arrays.asList(4, 6, 1, 2, 7);
        MyCompare myCompare = new MyCompare();
        List<Integer> list2 = Arrays.asList(4, 6, 1, 2, 7);
        MyCompare myCompare2 = new MyCompare();
        List<Integer> list3 = Arrays.asList(4, 6, 1, 2, 7);

        // Lambda表达式
        Collections.sort(list, (o1, o2) -> myCompare.compare(o1, o2));
        System.out.println("对象方法引用 - Lambda表达式 " + list);
        // 对象方法引用
        Collections.sort(list2, myCompare2::compare);
        System.out.println("对象方法引用 - 对象::非静态方法 " + list2);
        // 对象方法引用
        Collections.sort(list3, this::compare);
        System.out.println("对象方法引用 - this::非静态方法 " + list3);
    }

    /**
     * 类方法引用
     * 如果在引用某一个对象的方法时，而这个对象本身又是Lambda表达式的一个参数，并且其他参数（或无参）可以对应到该对象方法的参数列表，此时可以使用类方法引用进行简化。
     */
    public void test_9() {
        List<Integer> list = Arrays.asList(4, 6, 1, 2, 7);
        List<Integer> list2 = Arrays.asList(4, 6, 1, 2, 7);
        // 使用Lambda表达式实现
        Collections.sort(list, (o1, o2) -> o1.compareTo(o2));
        // 类方法引用实现
        Collections.sort(list2, Integer::compareTo);
    }

    /**
     * 构造方法引用 - 无参
     * 如果我们要通过Lambda表达式来新建一个对象，并且这个对象的构造方法的参数列表和函数式接口中抽象方法的参数列表相对应时，我们可以采用构造方法引用来处理。
     */
    public void test_10() {
        Supplier<Person> p = () -> new Person();
        Person person = p.get();
        Supplier<Person> p1 = Person::new;
        Person person1 = p1.get();
    }

    /**
     * 构造方法引用 - 一个参数
     */
    public void test_11() {
        Function<String, Person> p = (code) -> new Person(code);
        Person person = p.apply("C01001");
        Function<String, Person> p1 = Person::new;
        Person person1 = p1.apply("C01001");
    }

    /**
     * 构造方法引用 - 两个参数
     */
    public void test_12() {
        BiFunction<String, String, Person> p = (code, name) -> new Person(code, name);
        Person person = p.apply("C01001", "小瓦匠");
        BiFunction<String, String, Person> p1 = Person::new;
        Person person1 = p1.apply("C01001", "小瓦匠");
    }

    /**
     * 构造方法引用 - 三个参数
     */
    public void test_13() {
        TriFunction<String, String, String, Person> p = (code, name, address) -> new Person(code, name, address);
        Person person = p.apply("C01001", "小瓦匠", "北京市");
        TriFunction<String, String, String, Person> p1 = Person::new;
        Person person1 = p1.apply("C01001", "小瓦匠", "北京市");
    }

    private int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }

}
